package cloudsvr

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	ak      = "ELKT2QGQN0H7AB4sbGhQrjCkUp8jKkZd"
	baseUrl = "http://api.map.baidu.com/reverse_geocoding/v3/"
)

type geocodingAbroadResponse struct {
	Status int `json:"status"`
	Result struct {
		Location struct {
			Lat float64 `json:"lat"`
			Lng float64 `json:"lng"`
		} `json:"location"`
		FormattedAddress string `json:"formatted_address"`
		Business         string `json:"business"`
		AddressComponent struct {
			Country         string `json:"country"`
			CountryCode     int    `json:"country_code"`
			CountryCodeIso  string `json:"country_code_iso"`
			CountryCodeIso2 string `json:"country_code_iso2"`
		} `json:"addressComponent"`
	} `json:"result"`
}

func (m *geocodingAbroadResponse) String() string {
	var result = m.Result
	var addr = result.AddressComponent
	return fmt.Sprintf("<%d, [%v, %v], [%s], [%s], [%s, %d, %s, %s]>",
		m.Status,
		result.Location.Lat, result.Location.Lng,
		result.FormattedAddress,
		result.Business,
		addr.Country, addr.CountryCode, addr.CountryCodeIso, addr.CountryCodeIso2,
	)
}

type geocodingAbroadRequest struct {
	Location     string
	Coordtype    string
	RetCoordType string
	Radius       int
	Ak           string
	Output       string
}

func fromLoc(lat, lon float64) *geocodingAbroadRequest {
	return &geocodingAbroadRequest{
		Location:     fmt.Sprintf("%v,%v", lat, lon),
		Ak:           ak,
		Coordtype:    "wgs84ll",
		RetCoordType: "bd09ll",
		Radius:       10,
		Output:       "json",
	}
}

func (m *geocodingAbroadRequest) Encode() string {
	var u = make(url.Values)
	u.Add("location", m.Location)
	u.Add("coordtype", m.Coordtype)
	u.Add("ret_coordtype", m.RetCoordType)
	u.Add("radius", fmt.Sprintf("%d", m.Radius))
	u.Add("ak", m.Ak)
	u.Add("output", m.Output)

	return u.Encode()
}

func GeocodingAbroad(latitude, longitude float64) error {
	abroadReq := fromLoc(latitude, longitude)
	client := &http.Client{}

	fullUrl := baseUrl + "?" + abroadReq.Encode()
	//println(fullUrl)
	req, err := http.NewRequest("GET", fullUrl, nil)
	if err != nil {
		return errors.Wrap(err, "new request failed")
	}

	rsp, err := client.Do(req)
	if err != nil {
		return errors.Wrap(err, "execute http request failed")
	}
	if rsp.StatusCode != 200 {
		return errors.New("response not match 200")
	}
	defer func() {
		err = rsp.Body.Close()
		if err != nil {
			println("close http response body failed")
		}
	}()

	rspBody, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return errors.Wrap(err, "read http response body failed")
	}

	var out geocodingAbroadResponse
	err = json.Unmarshal(rspBody, &out)
	if err != nil {
		return errors.Wrap(err, "json unmarshal failed")
	}

	if out.Status != 0 {
		return errors.New("status code not match zero")
	}

	println(out.String())
	return nil
}
